package ee.logsimulator.ui;

import ee.logsimulator.Logsimulator;
import ee.logsimulator.Model;
import ee.logsimulator.data.Actor;
import ee.logsimulator.data.Clazz;
import ee.logsimulator.data.Mode;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.ScrollPane;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JPanel;

public class FilterPage extends MessageDialog {
  private static final long serialVersionUID = 1L;
  private Map<Actor, JCheckBox> sourceBoxes = new HashMap<Actor, JCheckBox>();
  private Map<Actor, JCheckBox> targetBoxes = new HashMap<Actor, JCheckBox>();
  private Model model;

  public FilterPage(final Logsimulator frame, Model m) {
    super(frame, "", true);
    this.model = m;

    JPanel panel = new JPanel();
    panel.setBackground(Color.BLACK);
    panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));

    if (model.getMode() == Mode.RESTO_DRUID) {
      panel.add(getActors("Choose the druid", true, true));
    } else {
      panel.add(getActors("Sources", true, false));
      panel.add(getActors("Targets", false, false));
    }

    ScrollPane scroll = new ScrollPane();
    scroll.add(panel);
    add(scroll, BorderLayout.CENTER);

    JButton ok = new JButton("OK");
    add(ok, BorderLayout.SOUTH);
    ok.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        model.simulate(false);
        frame.updateLabel();
        frame.updateSimulate();
        dispose();
      }
    });

    pack();
    Dimension size = panel.getSize();
    if (size.width > frame.getWidth() - 200) {
      size.width = frame.getWidth() - 200;
    }
    if (size.height > frame.getHeight() - 200) {
      size.height = frame.getHeight() - 200;
      size.width = size.width + 24;
    }
    scroll.setSize(size);
    pack();
    setResizable(false);
    setLocationRelativeTo(frame);
    setVisible(true);
  }

  private JPanel getActors(String title, final boolean source, boolean onlyDruids) {
    JPanel sources = new JPanel();
    sources.setBackground(Color.BLACK);
    sources.setLayout(new BoxLayout(sources, BoxLayout.PAGE_AXIS));

    final JCheckBox main = new JCheckBox(title);
    main.setBackground(Color.BLACK);
    main.setForeground(Color.WHITE);
    main.setAlignmentX(Component.LEFT_ALIGNMENT);
    Set<Actor> filter = source ? model.getSourceFilteredActors() : model.getTargetFilteredActors();
    Set<Actor> actors = source ? model.getSourceActors() : model.getTargetActors();
    main.setSelected(filter.size() == actors.size());
    main.setFont(main.getFont().deriveFont(20f));
    main.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        Set<Actor> filter = source ? model.getSourceFilteredActors() : model.getTargetFilteredActors();
        if (main.isSelected()) {
          Set<Actor> actors = source ? model.getSourceActors() : model.getTargetActors();
          for (Actor a : actors) {
            filter.add(a);
          }
        } else {
          filter.clear();
        }
        updateBoxes(source ? sourceBoxes : targetBoxes, filter);
      }
    });
    sources.add(main);
    for (final Actor a : source ? model.getSourceActors() : model.getTargetActors()) {
      if (onlyDruids && Clazz.fromName(a.getActorClass()) != Clazz.DRUID) {
        continue;
      }
      JCheckBox check = new JCheckBox(a.getName());
      check.setBackground(Color.BLACK);
      check.setAlignmentX(Component.LEFT_ALIGNMENT);
      check.setForeground(Clazz.fromName(a.getActorClass()).getColor());
      check.setSelected(filter.contains(a));
      check.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          Set<Actor> actors = source ? model.getSourceActors() : model.getTargetActors();
          Set<Actor> filter = source ? model.getSourceFilteredActors() : model.getTargetFilteredActors();
          if (filter.contains(a)) {
            filter.remove(a);
          } else {
            filter.add(a);
          }
          main.setSelected(filter.size() == actors.size());
        }
      });
      if (source) {
        sourceBoxes.put(a, check);
      } else {
        targetBoxes.put(a, check);
      }
      sources.add(check);
    }
    return sources;
  }

  private void updateBoxes(Map<Actor, JCheckBox> boxes, Set<Actor> filteredActors) {
    for (Entry<Actor, JCheckBox> e : boxes.entrySet()) {
      e.getValue().setSelected(filteredActors.contains(e.getKey()));
    }
  }
}
